﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.ComponentModel.Composition;
using System.Threading;

namespace Steve
{
    public abstract class ContentRepository
    {
        const string ContentDirectoryKey = "ContentDirectory";
        const string LogCategory = "Steve-ContentRepository";

        [Import]
        public IConfiguration Config { get; set; }
        [Import]
        public ICacheService Cache { get; set; }
        [Import]
        public ILoggingService Log { get; set; }
        
        public abstract IEnumerable<Tuple<Guid, int>> GetUpdatedContentIds(DateTime? updatedSince);

        [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
        public DirectoryNode<Content,ContentNodeMetadata> GetContentDirectoryRoot()
        {
            return Cache.GetValue<DirectoryNode<Content, ContentNodeMetadata>>(CacheType.ContentDirectory, ContentDirectoryKey, Config.DataCacheTtl, () => BuildContentDirectoryCache());
        }

        //TODO: make dictionary?
        [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
        protected abstract IEnumerable<Tuple<string, Guid>> GetContentPaths();

        private DirectoryNode<Content, ContentNodeMetadata> BuildContentDirectoryCache()
        {
            Log.Info(LogCategory, "Begin content dir cache build");

            var root = new DirectoryNode<Content, ContentNodeMetadata>("content-root", true);

            Log.Info(LogCategory, "begin get content paths");

            var paths = GetContentPaths();

            Log.Info(LogCategory, "begin url build");

            DirectoryNode<Content, ContentNodeMetadata>.BuildCacheFromUrlObjects(root, paths, t => new ContentNodeMetadata(t.Item1, t.Item2), t => () => GetContent(t.Item2, null, false));

            Log.Info(LogCategory, "end content dir cache build");

            return root;
        }

        public IEnumerable<Tuple<Content, float?>> GetContentByCategories(IEnumerable<string> requiredCategoryNames, IEnumerable<string> optionalCategoryNames, bool includeRelevancy, bool approvedOnly, int count)
        {
            return GetContentByCategories(requiredCategoryNames, optionalCategoryNames, includeRelevancy, approvedOnly, count, null, null, null);
        }

        public Content GetContent(Guid id)
        {
            return GetContent(id, null, true);
        }

        public IEnumerable<Tuple<Content, float>> GetContentSimilarToContent(Guid similarToContentId, bool approvedOnly, int count)
        {
            return GetContentSimilarToContent(similarToContentId, approvedOnly, count, null, null);
        }

        public abstract Content GetContent(Guid id, int? revision, bool approvedOnly);
        public abstract IEnumerable<string> GetContentCategories(Guid contentId);
        public abstract IEnumerable<Tuple<Content, float?>> GetContentByCategories(IEnumerable<string> requiredCategoryNames, IEnumerable<string> optionalCategoryNames, bool includeRelevancy, bool approvedOnly, int count, Guid? excludeContentId, string onlyContentTypeName, Guid? unreadByMembershipId);
        public abstract IEnumerable<Tuple<Content, float>> GetContentSimilarToContent(Guid similarToContentId, bool approvedOnly, int count, string onlyContentTypeName, Guid? unreadByMembershipId);
        public abstract Content GetContentForSiteUrl(Guid siteUrlId, bool approvedOnly);

        public abstract Stream GetContentData(Guid id);
    }
}
